/*
 * Copyright (C) 2005 - 2013 MaNGOS <http://www.getmangos.com/>
 *
 * Copyright (C) 2008 - 2013 Trinity <http://www.trinitycore.org/>
 *
 * Copyright (C) 2010 - 2013 ProjectSkyfire <http://www.projectskyfire.org/>
 *
 * Copyright (C) 2011 - 2013 ArkCORE <http://www.arkania.net/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#ifndef __ARKCORE_REPUTATION_MGR_H
#define __ARKCORE_REPUTATION_MGR_H

#include "Common.h"
#include "SharedDefines.h"
#include "Language.h"
#include "DBCStructure.h"
#include "QueryResult.h"
#include <map>

static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] =
{ LANG_REP_HATED, LANG_REP_HOSTILE, LANG_REP_UNFRIENDLY, LANG_REP_NEUTRAL, LANG_REP_FRIENDLY, LANG_REP_HONORED, LANG_REP_REVERED, LANG_REP_EXALTED };

enum FactionFlags
{
    FACTION_FLAG_NONE = 0x00,          // no faction flag
    FACTION_FLAG_VISIBLE = 0x01,          // makes visible in client (set or can be set at interaction with target of this faction)
    FACTION_FLAG_AT_WAR = 0x02,          // enable AtWar-button in client. player controlled (except opposition team always war state), Flag only set on initial creation
    FACTION_FLAG_HIDDEN = 0x04,          // hidden faction from reputation pane in client (player can gain reputation, but this update not sent to client)
    FACTION_FLAG_INVISIBLE_FORCED = 0x08,          // always overwrite FACTION_FLAG_VISIBLE and hide faction in rep.list, used for hide opposite team factions
    FACTION_FLAG_PEACE_FORCED = 0x10,          // always overwrite FACTION_FLAG_AT_WAR, used for prevent war with own team factions
    FACTION_FLAG_INACTIVE = 0x20,          // player controlled, state stored in characters.data (CMSG_SET_FACTION_INACTIVE)
    FACTION_FLAG_RIVAL = 0x40,          // flag for the two competing outland factions
    FACTION_FLAG_SPECIAL = 0x80
// horde and alliance home cities and their northrend allies have this flag
};

typedef uint32 RepListID;
struct FactionState
{
    uint32 ID;
    RepListID ReputationListID;
    uint8 Flags;
    int32 Standing;
    bool needSend;
    bool needSave;
};

typedef std::map<RepListID, FactionState> FactionStateList;
typedef std::map<uint32, ReputationRank> ForcedReactions;

class Player;

class ReputationMgr
{
public:
    // constructors and global modifiers
    explicit ReputationMgr (Player* owner) :
            m_player(owner), m_visibleFactionCount(0), m_honoredFactionCount(0), m_reveredFactionCount(0), m_exaltedFactionCount(0)
    {
    }
    ~ReputationMgr ()
    {
    }

    void SaveToDB (SQLTransaction& trans);
    void LoadFromDB (PreparedQueryResult result);
public:
    // statics
    static const int32 PointsInRank[MAX_REPUTATION_RANK];
    static const int32 Reputation_Cap = 42999;
    static const int32 Reputation_Bottom = -42000;

    static ReputationRank ReputationToRank (int32 standing);
public:
    // accessors
    uint8 GetVisibleFactionCount () const
    {
        return m_visibleFactionCount;
    }
    uint8 GetHonoredFactionCount () const
    {
        return m_honoredFactionCount;
    }
    uint8 GetReveredFactionCount () const
    {
        return m_reveredFactionCount;
    }
    uint8 GetExaltedFactionCount () const
    {
        return m_exaltedFactionCount;
    }

    FactionStateList const& GetStateList () const
    {
        return m_factions;
    }

    FactionState const* GetState (FactionEntry const* factionEntry) const
    {
        return factionEntry->reputationListID >= 0 ? GetState(factionEntry->reputationListID) : NULL;
    }

    FactionState const* GetState (RepListID id) const
    {
        FactionStateList::const_iterator repItr = m_factions.find(id);
        return repItr != m_factions.end() ? &repItr->second : NULL;
    }

    bool IsAtWar (uint32 faction_id) const;
    bool IsAtWar (FactionEntry const* factionEntry) const;

    int32 GetReputation (uint32 faction_id) const;
    int32 GetReputation (FactionEntry const* factionEntry) const;
    int32 GetBaseReputation (FactionEntry const* factionEntry) const;

    ReputationRank GetRank (FactionEntry const* factionEntry) const;
    ReputationRank GetBaseRank (FactionEntry const* factionEntry) const;
    uint32 GetReputationRankStrIndex (FactionEntry const* factionEntry)
    {
        return ReputationRankStrIndex[GetRank(factionEntry)];
    }
    ;

    ReputationRank const* GetForcedRankIfAny (FactionTemplateEntry const* factionTemplateEntry) const
    {
        ForcedReactions::const_iterator forceItr = m_forcedReactions.find(factionTemplateEntry->faction);
        return forceItr != m_forcedReactions.end() ? &forceItr->second : NULL;
    }

public:
    // modifiers
    bool SetReputation (FactionEntry const* factionEntry, int32 standing)
    {
        return SetReputation(factionEntry, standing, false);
    }
    bool ModifyReputation (FactionEntry const* factionEntry, int32 standing)
    {
        return SetReputation(factionEntry, standing, true);
    }

    void SetVisible (FactionTemplateEntry const* factionTemplateEntry);
    void SetVisible (FactionEntry const* factionEntry);
    void SetAtWar (RepListID repListID, bool on);
    void SetInactive (RepListID repListID, bool on);

    void ApplyForceReaction (uint32 faction_id, ReputationRank rank, bool apply);

public:
    // senders
    void SendInitialReputations ();
    void SendForceReactions ();
    void SendState (FactionState const* faction);
    void SendStates ();

private:
    // internal helper functions
    void Initialize ();
    uint32 GetDefaultStateFlags (FactionEntry const* factionEntry) const;
    bool SetReputation (FactionEntry const* factionEntry, int32 standing, bool incremental);
    bool SetOneFactionReputation (FactionEntry const* factionEntry, int32 standing, bool incremental);
    void SetVisible (FactionState* faction);
    void SetAtWar (FactionState* faction, bool atWar) const;
    void SetInactive (FactionState* faction, bool inactive) const;
    void SendVisible (FactionState const* faction) const;
    void UpdateRankCounters (ReputationRank old_rank, ReputationRank new_rank);
private:
    Player* m_player;
    FactionStateList m_factions;
    ForcedReactions m_forcedReactions;
    uint8 m_visibleFactionCount :8;
    uint8 m_honoredFactionCount :8;
    uint8 m_reveredFactionCount :8;
    uint8 m_exaltedFactionCount :8;
};

#endif
